"""
History management for Q&A records from LLM clients.
"""

import json
import os
from pathlib import Path
from typing import List, Optional, Dict, Any
from datetime import datetime, timedelta
from dataclasses import dataclass


@dataclass
class QAEntry:
    """Represents a single Q&A entry."""
    
    id: int
    question: str
    answer: str
    model: str  # qwen, deepseek, or oss
    timestamp: datetime
    system_prompt: Optional[str] = None
    chinese_mode: bool = False
    domain: Optional[str] = None
    context: Optional[Dict[str, str]] = None
    response_time: Optional[float] = None  # in seconds
    tokens_used: Optional[int] = None
    
    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for JSON serialization."""
        return {
            'id': self.id,
            'question': self.question,
            'answer': self.answer,
            'model': self.model,
            'timestamp': self.timestamp.isoformat() if self.timestamp else None,
            'system_prompt': self.system_prompt,
            'chinese_mode': self.chinese_mode,
            'domain': self.domain,
            'context': self.context,
            'response_time': self.response_time,
            'tokens_used': self.tokens_used
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'QAEntry':
        """Create QAEntry from dictionary."""
        return cls(
            id=data['id'],
            question=data['question'],
            answer=data['answer'],
            model=data['model'],
            timestamp=datetime.fromisoformat(data['timestamp']) if data['timestamp'] else None,
            system_prompt=data.get('system_prompt'),
            chinese_mode=data.get('chinese_mode', False),
            domain=data.get('domain'),
            context=data.get('context'),
            response_time=data.get('response_time'),
            tokens_used=data.get('tokens_used')
        )
    
    @property
    def question_preview(self) -> str:
        """Get a preview of the question (first 50 characters)."""
        return self.question[:50] + "..." if len(self.question) > 50 else self.question
    
    @property
    def answer_preview(self) -> str:
        """Get a preview of the answer (first 100 characters)."""
        return self.answer[:100] + "..." if len(self.answer) > 100 else self.answer


class QAHistoryManager:
    """Manages storage and retrieval of Q&A history."""
    
    def __init__(self, storage_file: Optional[str] = None):
        """Initialize history manager."""
        if storage_file is None:
            # Use XDG cache directory standard: ~/.cache/llm-clients/qa_history.json
            cache_dir = Path.home() / ".cache" / "llm-clients"
            storage_file = str(cache_dir / "qa_history.json")
        
        self.storage_file = Path(storage_file)
        self._ensure_storage_file()
    
    def _ensure_storage_file(self):
        """Ensure storage file exists."""
        if not self.storage_file.exists():
            self.storage_file.parent.mkdir(parents=True, exist_ok=True)
            self._save_data({"entries": [], "next_id": 1})
    
    def _load_data(self) -> Dict[str, Any]:
        """Load data from storage file."""
        try:
            with open(self.storage_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except (json.JSONDecodeError, FileNotFoundError):
            return {"entries": [], "next_id": 1}
    
    def _save_data(self, data: Dict[str, Any]):
        """Save data to storage file."""
        # Create backup
        if self.storage_file.exists():
            backup_file = self.storage_file.with_suffix('.json.backup')
            try:
                self.storage_file.rename(backup_file)
            except OSError:
                pass  # Ignore backup creation failures
        
        try:
            with open(self.storage_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=2, default=str, ensure_ascii=False)
        except Exception as e:
            # Restore backup if save failed
            backup_file = self.storage_file.with_suffix('.json.backup')
            if backup_file.exists():
                try:
                    backup_file.rename(self.storage_file)
                except OSError:
                    pass
            raise e
        else:
            # Remove backup after successful save
            backup_file = self.storage_file.with_suffix('.json.backup')
            if backup_file.exists():
                try:
                    backup_file.unlink()
                except OSError:
                    pass
    
    def add_entry(self, question: str, answer: str, model: str, **kwargs) -> QAEntry:
        """Add a new Q&A entry."""
        data = self._load_data()
        
        entry = QAEntry(
            id=data["next_id"],
            question=question,
            answer=answer,
            model=model,
            timestamp=datetime.now(),
            system_prompt=kwargs.get('system_prompt'),
            chinese_mode=kwargs.get('chinese_mode', False),
            domain=kwargs.get('domain'),
            context=kwargs.get('context'),
            response_time=kwargs.get('response_time'),
            tokens_used=kwargs.get('tokens_used')
        )
        
        data["entries"].append(entry.to_dict())
        data["next_id"] += 1
        
        self._save_data(data)
        return entry
    
    def get_entries(self, limit: Optional[int] = None,
                   model_filter: Optional[str] = None,
                   question_filter: Optional[str] = None,
                   chinese_only: bool = False,
                   recent_days: Optional[int] = None) -> List[QAEntry]:
        """Get Q&A entries with optional filtering."""
        data = self._load_data()
        entries = [QAEntry.from_dict(entry_data) for entry_data in data["entries"]]
        
        # Apply filters
        if model_filter:
            entries = [e for e in entries if e.model == model_filter]
        
        if question_filter:
            entries = [e for e in entries if question_filter.lower() in e.question.lower()]
        
        if chinese_only:
            entries = [e for e in entries if e.chinese_mode]
        
        if recent_days:
            cutoff_date = datetime.now() - timedelta(days=recent_days)
            entries = [e for e in entries if e.timestamp and e.timestamp > cutoff_date]
        
        # Sort by timestamp (newest first)
        entries.sort(key=lambda x: x.timestamp or datetime.min, reverse=True)
        
        if limit:
            entries = entries[:limit]
        
        return entries
    
    def get_entry(self, entry_id: int) -> Optional[QAEntry]:
        """Get a specific Q&A entry by ID."""
        data = self._load_data()
        
        for entry_data in data["entries"]:
            if entry_data["id"] == entry_id:
                return QAEntry.from_dict(entry_data)
        
        return None
    
    def delete_entry(self, entry_id: int) -> bool:
        """Delete a specific Q&A entry by ID."""
        data = self._load_data()
        
        original_count = len(data["entries"])
        data["entries"] = [e for e in data["entries"] if e["id"] != entry_id]
        
        if len(data["entries"]) < original_count:
            self._save_data(data)
            return True
        return False
    
    def cleanup_old_entries(self, days: int = 90):
        """Remove old Q&A entries."""
        cutoff_date = datetime.now() - timedelta(days=days)
        data = self._load_data()
        
        entries_to_keep = []
        for entry_data in data["entries"]:
            entry = QAEntry.from_dict(entry_data)
            if entry.timestamp and entry.timestamp > cutoff_date:
                entries_to_keep.append(entry_data)
        
        original_count = len(data["entries"])
        data["entries"] = entries_to_keep
        
        if len(data["entries"]) < original_count:
            self._save_data(data)
            return original_count - len(data["entries"])
        return 0
    
    def get_statistics(self) -> Dict[str, Any]:
        """Get statistics about Q&A entries."""
        entries = self.get_entries()
        
        total_entries = len(entries)
        qwen_entries = len([e for e in entries if e.model == "qwen"])
        deepseek_entries = len([e for e in entries if e.model == "deepseek"])
        oss_entries = len([e for e in entries if e.model == "oss"])
        chinese_entries = len([e for e in entries if e.chinese_mode])
        
        # Recent activity (last 7 days)
        recent_entries = self.get_entries(recent_days=7)
        recent_count = len(recent_entries)
        
        # Average response time
        response_times = [e.response_time for e in entries if e.response_time]
        avg_response_time = sum(response_times) / len(response_times) if response_times else None
        
        return {
            "total_entries": total_entries,
            "qwen_entries": qwen_entries,
            "deepseek_entries": deepseek_entries,
            "oss_entries": oss_entries,
            "chinese_entries": chinese_entries,
            "recent_entries": recent_count,
            "avg_response_time": avg_response_time,
            "storage_file": str(self.storage_file)
        }
    
    def search_entries(self, query: str, limit: Optional[int] = 20) -> List[QAEntry]:
        """Search entries by question or answer content."""
        entries = self.get_entries()
        matching_entries = []
        
        query_lower = query.lower()
        for entry in entries:
            if (query_lower in entry.question.lower() or 
                query_lower in entry.answer.lower()):
                matching_entries.append(entry)
        
        if limit:
            matching_entries = matching_entries[:limit]
        
        return matching_entries
